﻿using System;
using System.IO;

#if !PCL
using System.Runtime.Serialization.Formatters.Binary;
#endif

namespace OmniKits.Extensions
{
    using NullGuard;

    [NullGuard(ValidationFlags.None)]
    public static class ObjectExtensions
    {
#pragma warning disable 1591

#if !PCL
        private static Lazy<BinaryFormatter> LazyBinaryFormatterInstance = new Lazy<BinaryFormatter>();
#endif

        public static T As<T>(this object @this)
            where T : class
        {
            return @this as T;
        }

        public static T? AsNullable<T>(this object @this)
            where T : struct
        {
            return @this as T?;
        }

        public static bool Is(this object @this, object that)
        {
            return Equals(@this, that);
        }
        public static bool IsNot(this object @this, object that)
        {
            return !Equals(@this, that);
        }

#if !PCL
        /// <summary>
        /// Deep copy, available to seralizable objects only.
        /// </summary>
        public static T DeepCopy<T>(this T @this)
        {
            if (@this == null) throw new ArgumentNullException();

            var formatter = LazyBinaryFormatterInstance.Value;
            using (var holder = new MemoryStream())
            {
                formatter.Serialize(holder, @this);
                holder.Position = 0;
                return (T)formatter.Deserialize(holder);
            }
        }
#endif

        public static T CastTo<T>(this object @this)
        {
            return (T)@this;
        }

        public static T Do<T>(this T @this, Action<T> action)
        {
            if (action == null)
                throw new ArgumentNullException(nameof(action));

            action(@this);
            return @this;
        }

        public static TResult Do<TSource, TResult>(this TSource source, Func<TSource, TResult> func)
        {
            if (func == null)
                throw new ArgumentNullException(nameof(func));

            return func(source);
        }
    }
}
